#include "CharsetConvert.h"
#include <nsComponentManagerUtils.h>
#include <algorithm>

const char* tellenc(const unsigned char* const buffer, const size_t len);
void init_utf8_char_table();

extern bool is_valid_latin1;


CCharsetConvert CCharsetConvert::ins;

CCharsetConvert::CCharsetConvert(void)
: m_fileEncode("gb2312"), m_local("gb2312")
{
	m_converter = do_CreateInstance(NS_ISCRIPTABLEUNICODECONVERTER_CONTRACTID);
	init_utf8_char_table();
}

CCharsetConvert::~CCharsetConvert(void)
{
}

void CCharsetConvert::SetFileEncode(const std::string &encode)
{
	m_fileEncode = encode;
}

void CCharsetConvert::SetLocal(const std::string &encode)
{
	m_local = encode;
}

std::string CCharsetConvert::GetLocal()
{
	return m_local;
}

nsString CCharsetConvert::ConvertToUnicode(const nsACString &in)
{
	m_converter->SetCharset(m_fileEncode.c_str());
	nsString out;
	m_converter->ConvertToUnicode(in, out);
	return out;
}

nsCString CCharsetConvert::ConvertToLocal(const nsAString &in)
{
	m_converter->SetCharset(m_local.c_str());
	nsCString out, end;
	m_converter->ConvertFromUnicode(in, out);
	m_converter->Finish(end);
	out.Append(end);
	return out;
}

#ifndef TELLENC_BUFFER_SIZE
#define TELLENC_BUFFER_SIZE 200000
#endif

std::string CCharsetConvert::DetectEncode(const std::string &file)
{
	FILE* fp = fopen(file.c_str(), "rb");
	if (fp == NULL) 
	{
		return "";
	}

	unsigned char buffer[TELLENC_BUFFER_SIZE];
	size_t len;
	len = fread(buffer, 1, sizeof buffer, fp);

	if (const char* enc = tellenc(buffer, len)) {
		if (is_valid_latin1 && strcmp(enc, "windows-1252") == 0) 
		{
			return "latin1";
		} 
		else 
		{
			return enc;
		}
	} 
	else 
	{
		return "unknown";
	}

	fclose(fp);
}

std::string CCharsetConvert::ConvertUTF16ToUTF8(const std::string &file)
{
	FILE* fp = fopen(file.c_str(), "rb");

	unsigned char buffer[TELLENC_BUFFER_SIZE];
	size_t len = fread(buffer, 1, sizeof buffer, fp);

	int i = 2;
	if (buffer[2] == 0)
	{
		i = 3;
	}

	nsString in;
	in.Assign((PRUnichar*)(buffer+i), (len - i)/2);
	nsCString out;
	NS_UTF16ToCString(in, NS_CSTRING_ENCODING_UTF8, out);

	std::string str = out.get();
	fclose(fp);

	str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());

	return str;

}
